#ifndef _ZERO_INCLUDE_CORBA_H
#define _ZERO_INCLUDE_CORBA_H
#include "include/config.h"
#include "include/lib.h"
#include "include/cxxstd.h"

using namespace std;

namespace zero
{
// SII/SSI: static interface/server invoke <([{
class DataEncoder
{
	protected:
		char* buffer;
		int pos;

	public:
		__extension__ enum HeaderFlag {
			NORMAL		= 0x0,
		};

		DataEncoder(char* b) : buffer(b), pos(0) {}

		void input(void* v, int length) { memcpy(v, buffer + pos, length); pos += length; }

		void struct_begin() {}
		void struct_end() {}

		void setHeader(HeaderFlag flag) { assert(pos == 0); buffer[pos++] = flag; }
};

class DataDecoder : public DataEncoder
{
	public:
		DataDecoder(char* b) : DataEncoder(b) {}

		void output(void* v, int length) { memcpy(buffer + pos, v, length); pos += length; }

		HeaderFlag getHeader() { assert(pos == 0); return (HeaderFlag) buffer[pos++]; }
};

interface StaticTypeInfo
{
	public:
		virtual std::size_t getLength() = 0;

		virtual void marshal(DataEncoder&, void*) = 0;
		virtual void demarshal(DataDecoder&, void*) = 0;
};

class Long : virtual public StaticTypeInfo
{
	public:
		Long() {}
		virtual ~Long();

		virtual std::size_t getLength();

		virtual void marshal(DataEncoder& out, void* v);
		virtual void demarshal(DataDecoder& in, void* v);
};
extern Long tiLong;

class Short : virtual public StaticTypeInfo
{
	public:
		Short() {}
		virtual ~Short();

		virtual std::size_t getLength();

		virtual void marshal(DataEncoder& out, void* v);
		virtual void demarshal(DataDecoder& in, void* v);
};
extern Short tiShort;

class Char : virtual public StaticTypeInfo
{
	public:
		Char() {}
		virtual ~Char();

		virtual std::size_t getLength();

		virtual void marshal(DataEncoder& out, void* v);
		virtual void demarshal(DataDecoder& in, void* v);
};
extern Char tiChar;

class StaticAny
{
	public:
		__extension__ enum Flag {
			CALLEE_FREE		= 0x1,

			ARGUMENT_IN		= 0x10,
			ARGUMENT_OUT	= 0x20,
			ARGUMENT_INOUT	= ARGUMENT_IN | ARGUMENT_OUT,
			RESULT			= 0x40,
			EXCEPTION		= 0x80,
		};

	private:
		StaticTypeInfo* sti;
		Flag flag;
		void* value;

	public:
		explicit StaticAny(StaticTypeInfo* sti, Flag f, void* v) : sti(sti), flag(f), value(v) {}
		explicit StaticAny() {}
		~StaticAny() {}

		StaticTypeInfo* getSTI() { return sti; }
		Flag getFlag() { return flag; }
		void* getValue() { return value; }
		void setValue(void* v) { value = v; }
};

class StaticRequest
{
	protected:
		const char* opName;
		StaticAny* ex;
		StaticAny* result;
		int argIndex;
		StaticAny* args[10];
		DataDecoder* dd;
		DataEncoder* de;

	public:
		StaticRequest(const char* op) : opName(op) { argIndex = 0; memset(args, sizeof(args), 0); ex = NULL; }

		StaticRequest& operator << (StaticAny& sa) { args[argIndex++] = &sa; return *this; }
		void setResult(StaticAny* sa) { result = sa; }
		StaticAny* getResult() { return result; }
		void setException(StaticAny* sa) { ex = sa; }
		StaticAny* getException() { return ex; }
		void setDataEncoder(DataEncoder* de) { this->de = de; }
		DataEncoder* getDataEncoder() { return de; }
		void setDataDecoder(DataDecoder* dd) { this->dd = dd; }
		DataDecoder* getDataDecoder() { return dd; }
		const char* getOpName() const { return opName; }

		StaticAny* iterator(int index) { return args[index]; }
};

class StaticServerRequest : public StaticRequest
{
	public:
		StaticServerRequest(const char* op) : StaticRequest(op) {}
};
// }])>

// Basic Data Declaration <([{
class Object
{
	public:
		virtual ~Object();
};

class ServerObject : public Object
{
	public:
		virtual ~ServerObject();

		virtual void invoke(class StaticServerRequest& ssr) = 0;
};

class Exception : public exception, virtual public StaticTypeInfo
{
	public:
		virtual ~Exception() throw();

		virtual const char* what() const throw();

		virtual std::size_t getLength();
		virtual void marshal(DataEncoder& out, void* v);
		virtual void demarshal(DataDecoder& in, void* v);
};

__extension__ enum CalleeLocation
{
	IN_PROCESS,
	LOCAL_HOST,
	REMOTE,
};
// }])>

// poa and orb <([{
class POA;
class ORB
{
	public:
		POA* allocPOA();

		void registerServerObject(const char* ifName, ServerObject* so, void* ifEntry);
		void* query(const char* ifName, ServerObject** so, CalleeLocation* cl, void* stub);

		// Later method pair includes resource allocation/free inside corba subsystem.
		void invokeAsyn(StaticRequest& sr, Object& from, ServerObject& to, CalleeLocation cl);
		int maybeThrow(StaticRequest& sr, ...);

		void dealWithArgs(StaticServerRequest& ssr);
		void writeResults(StaticServerRequest& ssr);
		void writeException(StaticServerRequest& ssr, int order);

	private:
		struct
		{
			const char* ifName;
			ServerObject* so;
			void* ifEntry;
		} pool[1];
};
extern ORB orb;

class POA
{
	public:
		void publish(const char* ifName, ServerObject* so, void* ifEntry);

		void dealWithArgs(StaticServerRequest& ssr);
		void writeResults(StaticServerRequest& ssr);
		void writeException(StaticServerRequest& ssr, int order);
};
// }])>
}

void* operator new(std::size_t, zero::CalleeLocation) throw (std::bad_alloc);
#endif
// vim: foldmarker=<([{,}])> foldmethod=marker
